package com.spzx.product.configure;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
public class ThreadPoolConfig {


    /**
     * 创建并配置一个线程池。
     * 该方法通过 {@code @Bean} 注解定义为 Spring 容器中的一个 Bean，用于提供应用程序所需的线程池实例。
     * 线程池的核心线程数设置为当前机器的可用处理器数量，最大线程数为核心线程数的两倍，空闲线程的存活时间为 60 秒。
     * 使用有界队列（容量为 100）来控制任务的数量，并且自定义了拒绝策略：当线程池拒绝接收新任务时，
     * 会先让当前线程休眠 200 毫秒，然后再尝试将任务重新提交给线程池执行。
     *
     * @return 配置好的 {@link ThreadPoolExecutor} 实例，用于管理线程和任务执行。
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        // 获取当前机器的可用处理器数量作为核心线程数
        int corePoolSize = Runtime.getRuntime().availableProcessors();

        // 设置最大线程数为核心线程数的两倍，以提高并发处理能力
        int maximumPoolSize = corePoolSize * 2;

        // 设置空闲线程的存活时间为 60 秒，超过此时间后非核心线程会被回收
        long keepAliveTime = 60L;

        // 创建并返回线程池实例
        return new ThreadPoolExecutor(
                corePoolSize, // 1.核心线程数，即最小线程数
                maximumPoolSize, // 2.最大线程数，允许创建的最大线程数
                keepAliveTime, // 3.空闲线程的存活时间
                TimeUnit.SECONDS, // 4.时间单位为秒
                new ArrayBlockingQueue<>(100), // 5.使用有界队列，限制任务队列的最大长度为 100
                Executors.defaultThreadFactory(), // 6.使用默认的线程工厂创建线程

                // 7.自定义拒绝策略：当线程池无法接受新任务时，先让当前线程休眠 200 毫秒，再尝试重新提交任务
                (runnable, executor) -> {
                    try {
                        // 当线程池拒绝接收新任务时，让当前线程休眠 200 毫秒
                        Thread.sleep(200);
                    } catch (InterruptedException ignored) {
                        // 忽略中断异常
                    }
                    // 再次将拒绝的任务提交给线程池执行
                    executor.submit(runnable);
                }
        );
    }

}